package com.wstuo.common.rules.entity;

import com.wstuo.common.entity.BaseEntity;
import com.wstuo.common.security.utils.LanguageContent;
import com.wstuo.common.util.StringUtils;

import org.apache.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

/**
 * bean of package
 * 
 * @author <a href="mailto:376890523@qq.com">jeff</a>
 * @version 0.1 2010.9.28
 */
@SuppressWarnings({ "rawtypes", "serial" })
@Entity
public class RulePackage extends BaseEntity {
	public final static String PRIORITYMATRIX = "com.drools.drl.prioritymatrix";
	public final static String REQUESTFITSERVICES = "com.drools.drl.helpDeskRequest";
	public final static String AUTOUPDATE = "com.drools.drl.autoupdate";
	public final static String MAILTOREQUEST = "com.drools.drl.mailtorequest";
	public final static String PROCESSING = "com.drools.drl.processing";
	public final static String CHANGEAPPROVA = "com.drools.drl.changeApprova";
	public final static String CHANGEPROCESSING = "com.drools.drl.changeprocessing";
	/**
	 * package no
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long rulePackageNo;
	private static final Logger LOGGER = Logger.getLogger(RulePackage.class ); 
	/**
	 * package name
	 */
	private String packageName;

	/**
	 * import package name
	 */
	private String imports;
	/**
	 * package module
	 */
	private String module;
	/**
	 * variable
	 */
	private String globals;

	/**
	 * function
	 */
	private String functions;

	/**
	 * Path
	 */
	private String location;
	private String ruleFlag;
	private String flagName;
	private String rulePackageRemarks;// 规则包备注

	
	public String getModule() {
		return module;
	}

	public void setModule(String module) {
		this.module = module;
	}

	public String getRulePackageRemarks() {
		return rulePackageRemarks;
	}

	public void setRulePackageRemarks(String rulePackageRemarks) {
		this.rulePackageRemarks = rulePackageRemarks;
	}

	public String getFlagName() {
		return flagName;
	}

	public void setFlagName(String flagName) {
		this.flagName = flagName;
	}

	public String getRuleFlag() {
		return ruleFlag;
	}

	public void setRuleFlag(String ruleFlag) {
		this.ruleFlag = ruleFlag;
	}

	/**
	 * map of rule
	 */
	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumn(name = "rulePackageNo")
	private List<Rule> rules = new ArrayList<Rule>();

	public List<Rule> getRules() {
		return rules;
	}

	public void setRules(List<Rule> rules) {
		this.rules = rules;
	}

	public Long getRulePackageNo() {
		return rulePackageNo;
	}

	public void setRulePackageNo(Long rulePackageNo) {
		this.rulePackageNo = rulePackageNo;
	}

	public String getPackageName() {
		return packageName;
	}

	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public String getImports() {
		return imports;
	}

	public void setImports(String imports) {
		this.imports = imports;
	}

	public String getGlobals() {
		return globals;
	}

	public void setGlobals(String globals) {
		this.globals = globals;
	}

	public String getFunctions() {
		return functions;
	}

	public void setFunctions(String functions) {
		this.functions = functions;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	/**
	 * toString Method
	 */
	public String toString() {
		LanguageContent lc = LanguageContent.getInstance(); 
		String binding = null;
		StringBuffer buffer = new StringBuffer();
		BufferedReader br = new BufferedReader(new StringReader(imports));
		// 系统数据
		if (packageName.equals(lc.getContent("label.rulePackage.requestRule"))) {
			buffer.append("package "+RulePackage.REQUESTFITSERVICES);
		} else if (packageName.equals(lc.getContent("title.sla.autoUpdate"))) {
			buffer.append("package "+RulePackage.AUTOUPDATE);
		} else {
			buffer.append("package " + packageName);
		}
		buffer.append("\n");
		try {
			String line = null;
			while ((line = br.readLine()) != null) {
				buffer.append("import ");
				buffer.append(line);
			}
		} catch (IOException e) {
			LOGGER.error(e.getMessage());
		}
		buffer.append("\n\n");

		for (int i = 0; i < rules.size(); i++) {
			Rule rule = rules.get(i);
			if (rule.getDataFlag() != 99) {
				//规则头部
				buffer.append(structureDroolsHead(rule));
				//规则条件构造
				RulePattern pattern = rule.getCondition();
				if (pattern != null) {
					binding = pattern.getPatternBinding();
					buffer.append(structureDroolsConditions(pattern));
				}else {
					buffer.append("\ndto:RequestDTO(etitle matches \".*.*\")");
				}
				//规则动作构造
				buffer.append(structureDroolsAction(rule,binding));
			}
		}

		// 加入函数
		if (functions != null) {
			buffer.append(functions);
		}
		return buffer.toString();
	}
	
	/**
	 * drools head
	 * @param rule
	 * @return
	 */
	private String structureDroolsHead(Rule rule){
		StringBuffer buffer = new StringBuffer();
		buffer.append("rule \"" + rule.getRuleName() + "\"\n");
		if (rule.getSalience() != null) {
			buffer.append("    salience  " + rule.getSalience() + " \n");
		}

		buffer.append("    dialect \"mvel\"\n");
		buffer.append("    no-loop true \n");

		buffer.append("    lock-on-active true \n");
		buffer.append("    when");
		return buffer.toString();
	}
	/**
	 * 规则条件构造
	 * @param pattern
	 * @return
	 */
	private String structureDroolsConditions (RulePattern pattern){
		StringBuffer buffer = new StringBuffer();
		buffer.append("\n        ");
		buffer.append(pattern.getPatternBinding());
		buffer.append(":");
		buffer.append(pattern.getPatternType());
		buffer.append("((");
		
		// 上一个连接方式
		String previousJoinType = "";
		int count = 0;
		// 规则集条件构造
		for (RuleConstraint constraint : pattern.getConstraints()) {
			// 如果遇到And，则添加and条件连接
			if ("and".equals(previousJoinType)) {
				buffer.append("),(");
			} else {
				// 判断最后一个字符是否是(括号.
				if (!("(").equals(buffer.toString().substring(buffer.toString().length() - 1))){
					buffer.append(" || ");
				}
			}
			// 如果是Long和Integer类型的值，则直接等于
			if ("Long".equals(constraint.getDataType()) || "Integer".equals(constraint.getDataType())) {
				buffer.append(longIntegerType(constraint));
			} else if ("Long[]".equals(constraint.getDataType())) {
				buffer.append(longArrayType(constraint));
			} else {
				buffer.append(constraint.getPropertyName() + " "
						+ "\"" + constraint.getPropertyValue()
						+ "\"");
			}
			previousJoinType = constraint.getAndOr();
			count++;
			// 如果遍历到最后一个，则把结束的")"括号加上
			if (count == pattern.getConstraints().size()) {
				buffer.append(")");
			}
		}
		// 没有条件的情况下，默认添加包含所有
		if (pattern.getConstraints().size() == 0) {
			buffer.append("etitle matches \".*.*\")");
		}
		buffer.append(")");
		return buffer.toString();
	}
	
	private String structureDroolsAction(Rule rule,String binding){
		LanguageContent lc = LanguageContent.getInstance(); 
		StringBuffer buffer = new StringBuffer();
		buffer.append("\n    then \n        ");
		buffer.append("modify(");
		buffer.append(binding);
		buffer.append("){");
		if (packageName.equals(lc.getContent("title.sla.autoUpdate"))) {
			buffer.append(" autoUpdate=\"yes\" ");
			buffer.append("}");
			buffer.append("\nend\n ");
			buffer.append("\n ");
		} else {
			for (int j = 0; j < rule.getActions().size(); j++) {
				RuleAction action = rule.getActions().get(j);
				if (action.getSequence() > 1) {
					buffer.append(",");
				}
				buffer.append(action.getPropertyName());
				if ("Long".equals(action.getDataType())) {
					buffer.append("=");
					buffer.append(action.getGivenValue() + "L");
				} else if ("Integer".equals(action.getDataType())) {
					buffer.append("=");
					buffer.append(action.getGivenValue());
				} else {
					buffer.append("=\"");
					buffer.append(action.getGivenValue());
					buffer.append("\"");
				}
			}
			buffer.append("}");
			buffer.append("\nend\n ");
			buffer.append("\n ");
		}
		return buffer.toString();
	}
	
	/**
	 * Long and integer data type construction
	 * @param constraint
	 * @return drool string
	 */
	private String longIntegerType(RuleConstraint constraint){
		StringBuffer sb = new StringBuffer();
		if (constraint.getPropertyName().indexOf("notIn") != -1
				|| constraint.getPropertyName().indexOf("in") != -1) {
			sb.append(constraint.getPropertyName().replace("notIn","not in ")
					+ " (" + constraint.getPropertyValue()
					+ ")");
		} else {
			sb.append(constraint.getPropertyName()+ " " + constraint.getPropertyValue());
		}
		return sb.toString();
	}
	
	/**
	 * Long[] data type construction
	 * @param constraint
	 * @return drool string
	 */
	private String longArrayType(RuleConstraint constraint){
		String valueStr = constraint.getPropertyValue();
		StringBuffer pstr = new StringBuffer();
		pstr.append("(");
		if (StringUtils.hasText(valueStr)) {
			String[] strs = valueStr.split(",");
			for (String str : strs) {
				if ("(".equals(pstr.toString())) {
					if (constraint.getPropertyName().indexOf("notIn") == -1) {
						pstr.append(" ("
									+ constraint.getPropertyName().replace("in","contains ")
									+ str + "L) ");
					} else {
						pstr.append(" ("
								+ constraint.getPropertyName().replace("notIn","not contains ")
								+ str + "L) ");
					}

				} else {
					if (constraint.getPropertyName().indexOf("notIn") == -1) {
						pstr.append("|| ("
								+ constraint.getPropertyName().replace("in","contains ")
								+ str + "L) ");
					} else {
						pstr.append(",("
								+ constraint.getPropertyName().replace("notIn","not contains  ")
								+ str + "L) ");
					}
				}
			}
		}
		pstr.append(")");
		return pstr.toString();
	}
	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((flagName == null) ? 0 : flagName.hashCode());
		result = prime * result
				+ ((functions == null) ? 0 : functions.hashCode());
		result = prime * result + ((globals == null) ? 0 : globals.hashCode());
		result = prime * result + ((imports == null) ? 0 : imports.hashCode());
		result = prime * result
				+ ((location == null) ? 0 : location.hashCode());
		result = prime * result
				+ ((packageName == null) ? 0 : packageName.hashCode());
		result = prime * result
				+ ((ruleFlag == null) ? 0 : ruleFlag.hashCode());
		result = prime * result
				+ ((rulePackageNo == null) ? 0 : rulePackageNo.hashCode());
		result = prime
				* result
				+ ((rulePackageRemarks == null) ? 0 : rulePackageRemarks
						.hashCode());
		result = prime * result + ((rules == null) ? 0 : rules.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RulePackage other = (RulePackage) obj;
		if (flagName == null) {
			if (other.flagName != null)
				return false;
		} else if (!flagName.equals(other.flagName))
			return false;
		if (functions == null) {
			if (other.functions != null)
				return false;
		} else if (!functions.equals(other.functions))
			return false;
		if (globals == null) {
			if (other.globals != null)
				return false;
		} else if (!globals.equals(other.globals))
			return false;
		if (imports == null) {
			if (other.imports != null)
				return false;
		} else if (!imports.equals(other.imports))
			return false;
		if (location == null) {
			if (other.location != null)
				return false;
		} else if (!location.equals(other.location))
			return false;
		if (packageName == null) {
			if (other.packageName != null)
				return false;
		} else if (!packageName.equals(other.packageName))
			return false;
		if (ruleFlag == null) {
			if (other.ruleFlag != null)
				return false;
		} else if (!ruleFlag.equals(other.ruleFlag))
			return false;
		if (rulePackageNo == null) {
			if (other.rulePackageNo != null)
				return false;
		} else if (!rulePackageNo.equals(other.rulePackageNo))
			return false;
		if (rulePackageRemarks == null) {
			if (other.rulePackageRemarks != null)
				return false;
		} else if (!rulePackageRemarks.equals(other.rulePackageRemarks))
			return false;
		if (rules == null) {
			if (other.rules != null)
				return false;
		} else if (!rules.equals(other.rules))
			return false;
		return true;
	}
}
